package com.retrofit.starter.config;



import com.retrofit.starter.annotation.EnableRetrofit;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.ConstructorArgumentValues;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.filter.TypeFilter;

import java.io.IOException;
import java.util.Map;
import java.util.Set;

/**
 * @author shanchong
 * @date 2019-06-30
 **/
public class RetrofitBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar,
        EnvironmentAware, BeanFactoryAware,BeanDefinitionRegistryPostProcessor {

    private Environment environment;
    private BeanFactory beanFactory;

    private String value;

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }

    @Override
    public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) {
        final Map<String, Object> annotationAttributes = annotationMetadata.getAnnotationAttributes(EnableRetrofit.class.getName());
        final String value = (String) annotationAttributes.get("value");
        doScan(beanDefinitionRegistry, value);

    }

    @Override
    public void setEnvironment(Environment environment) {
        this.environment = environment;
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
    }

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
        final String scope = getValue();
        doScan(beanDefinitionRegistry, scope);
    }

    private void doScan(BeanDefinitionRegistry beanDefinitionRegistry, String value) {
        final RetrofitClassPathBeanDefinitionScanner scanner = new RetrofitClassPathBeanDefinitionScanner(beanDefinitionRegistry);
        scanner.addIncludeFilter(new TypeFilter() {
            @Override
            public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
                return true;
            }
        });
        final Set<BeanDefinitionHolder> beanDefinitionHolders = scanner.doScan(value);
        for (BeanDefinitionHolder beanDefinitionHolder : beanDefinitionHolders) {
            GenericBeanDefinition beanDefinition = (GenericBeanDefinition) beanDefinitionHolder.getBeanDefinition();
            final String beanClassName = beanDefinition.getBeanClassName();
            beanDefinition.setBeanClass(RetrofitFactoryBean.class);
            try {
                final ConstructorArgumentValues constructorArgumentValues = beanDefinition.getConstructorArgumentValues();
                constructorArgumentValues.addGenericArgumentValue(Class.forName(beanClassName));
                constructorArgumentValues.addGenericArgumentValue(environment);
                constructorArgumentValues.addGenericArgumentValue(beanFactory);
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
            beanDefinition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
        }
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {

    }
}